#include <sum_gpio.h>
#include <sum_rcu.h>
#include <sum_usart.h>
#include <sys_mem.h>
#include <util_trans.h>

#define APB2_FREQ_DEFAULT 48000000

// 设置PLL
static void _set_pll(void) {
	// 配置CFG0
	rcu_cfg0_para_s cfg0_para = {
		.set_sys_clock = RCU_CFG0_SYS_CLOCK_PLL,
		.ahb_psc = RCU_CFG0_AHB_SYS_NO_DIV,
		.apb1_psc = RCU_CFG0_APB_AHB_NO_DIV,
		.apb2_psc = RCU_CFG0_APB_AHB_NO_DIV,
		.adc_psc = RCU_CFG0_ADC_APB2_DIV_2,
		.pll_src = RCU_CFG0_PLL_IRC8M_DIV_2,
		.predv0_lsb = 0,
		.pll_freq_mul = RCU_CFG0_PLL_FREQ_MUL_12,
		.usbfs_psc = RCU_CFG0_USBFS_PLL_NO_DIV,
		.ckout0_src = RCU_CFG0_CKOUT0_NONE,
	};
	rcu_set_cfg_0(cfg0_para);

	// 开启PLL
	rcu_ctl_24_31_expl_s ctl_24_31 = {
		.pll_en = 1,
		.pll1_en = 0,
		.pll2_en = 0,
	};
	rcu_setup_pll(ctl_24_31);
}

// 等待PLL稳定
static inline void _wait_pll(void) {
	rcu_ctl_24_31_expl_s ctl_24_31;
	do {
		ctl_24_31 = rcu_read_pll_setup();
	} while (!ctl_24_31.is_pll_stable);
}

// RCU中将GPIOA和USART0上电
static void _enable_gpioa_usart0(void) {
	rcu_apb2_s apb2 = {
		.apb2_0_7.GPIOA = 1,
		.apb2_8_15.USART0 = 1,
	};
	rcu_apb2_en_di(apb2);
}

// 配置A9为AF输出，A10为浮空输入。
static void _setup_gpafio(void) {
	gpio_ctl_8_15_s ctl = {
		// A9的配置：低速输出、AF、推挽
		.pin9_ctl = GPIO_OUT_AF_PP_2MHZ,
		// A10的配置：输入、浮空
		.pin10_ctl = GPIO_IN_FLOAT,
	};
	gpio_setup_pin_8_15(GPIOA_Q, ctl);
}

// 使能USART0本身，以及其发送功能。
static void _enable_usart0_send(void) {
	usart_ctl0_expl_s ctl0 = {
		.trans_en = 1,
		.usart_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// 向串口阻塞发送1字节的函数，也是trans_write系列函数的参数。
static void _send(u32_s byte) {
	usart_wb_byte(USART0_Q, byte);
}

__attribute__((noreturn, section(".MAIN"))) void user_main(void) {
	// 未定义全局变量和静态局部变量，因此不需要scatter_load。
	// mem_scatter_load();
	_set_pll();
	_enable_gpioa_usart0();
	_setup_gpafio();
	usart_set_baud_rate(USART0_Q, 115200, APB2_FREQ_DEFAULT);
	_enable_usart0_send();

	_wait_pll();
	for (u32_s i = 0;; i++) {
		if (i << 10) {
			continue;
		}
		trans_write_str("If this sentence is printed normally, then "
				"PLL is configured sucessfully.\n",
				_send);
	}
}
